﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Atosenet
{
    public abstract class SingleExecuteQueue<T>
    {
        #region 成员

        private const int TASK_CHECK_INTERVAL = 100;

        private Thread _executeThread;
        private AutoResetEvent _resetEvent;

        private TaskPriority _priority = TaskPriority.Normal;

        #endregion


        #region 初始化

        public SingleExecuteQueue()
        {
            ExecuteQueue = new List<T>();
            _resetEvent = new AutoResetEvent(true);
            EnableThread = true;
        }

        #endregion


        #region 公开函数

        public void Start(int taskInterval)
        {
            _executeThread = new Thread(new ParameterizedThreadStart(ExecuteThread));
            _executeThread.Priority = GetThreadPriority(Priority);
            _executeThread.Name = "[SingleExecuteQueue] Execute Thread";
            _executeThread.IsBackground = true;
            EnableThread = true;
            _executeThread.Start(taskInterval);
        }

        public void Start()
        {
            Start(TASK_CHECK_INTERVAL);
        }

        public void Stop()
        {
            if (IsStarted)
            {
                EnableThread = false;
            }
        }

        public void ForceStop()
        {
            if (IsStarted)
            {
                EnableThread = false;
                _executeThread.Abort();
            }
        }

        public void Execute(T data)
        {
            ExecuteQueue.Add(data);
            _resetEvent.Set();
        }

        #endregion


        #region 核心函数

        private void ExecuteThread(object para)
        {
            int interval = (int)para;

            while (EnableThread)
            {
                if (ExecuteQueue.Count > 0)
                {
                    T data = default(T);

                    lock (ExecuteQueue)
                    {
                        data = ExecuteQueue[0];
                        ExecuteQueue.RemoveAt(0);
                    }

                    if (VerifyData(data))
                    {
                        Executing(data);
                    }
                    Thread.Sleep(interval);
                }
                else
                {
                    _resetEvent.WaitOne();
                }
            }
        }

        private void Executing(T data)
        {
            try
            {
                if (ExecutingProcess(data))
                    ExecutedCount++;
            }
            catch
            { }
        }

        protected abstract bool ExecutingProcess(T data);

        protected abstract bool VerifyData(T data);

        private ThreadPriority GetThreadPriority(TaskPriority priority)
        {
            ThreadPriority result = ThreadPriority.Normal;

            try
            {
                result = (ThreadPriority)Enum.Parse(typeof(ThreadPriority), priority.ToString(), true);
            }
            catch
            { }
            return result;
        }

        #endregion


        #region 属性

        private List<T> ExecuteQueue
        {
            get;
            set;
        }

        public long ExecutedCount
        {
            get;
            private set;
        }

        public int CurrentTaskCount
        {
            get { return ExecuteQueue == null ? 0 : ExecuteQueue.Count; }
        }

        public TaskPriority Priority
        {
            get { return _priority; }
            set
            {
                if (_priority != value)
                    _priority = value;

                if (_executeThread != null)
                    _executeThread.Priority = GetThreadPriority(value);
            }
        }

        public bool IsStarted
        {
            get { return _executeThread == null ? false : _executeThread.IsAlive; }
        }

        private bool EnableThread
        {
            get;
            set;
        }

        #endregion
    }

    public enum TaskPriority
    {
        Lowest = 1,
        BelowNormal = 2,
        Normal = 3,
        AboveNormal = 4,
        Highest = 5
    }
}
